package webcrawler;

import com.alibaba.fastjson.JSON;
import com.google.common.reflect.TypeToken;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ChinaIdCardAreaCode {

    private static final String jsonFileName = "./src/webcrawler/assets/ChinaAreaCode.json";

    private ChinaIdCardAreaCode() {
    }

    private static List<ChinaProvince> list = new ArrayList<>();

    public static void main(String[] args) {
        //syncAreaCodeFromWeb();
        //testLoadLocalData();
        testGetDates();
    }

    public static void testGetDates() {
        List<String> dates = getDateFromYear(getDateFromString(1970));
        for (int i = 0; i < dates.size(); i++) {
            System.out.println(dates.get(i));
        }
    }

    public static void testLoadLocalData() {
        loadChinaProvince();
        String provinceName = "天津";
        String cityName = "市辖区";
        List<ChinaAreaCode> areaCodes = getAreaCode(provinceName);
        for (int i = 0; i < areaCodes.size(); i++) {
            System.out.println(provinceName + " area code : " + areaCodes.get(i).getCode() + " " + areaCodes.get(i).getArea());
        }

        List<ChinaAreaCode> areaCodes2 = getAreaCode(provinceName, cityName);
        for (int i = 0; i < areaCodes2.size(); i++) {
            System.out.println(provinceName + " " + cityName + " area code : " + areaCodes2.get(i).getCode() + " " + areaCodes2.get(i).getArea());
        }

        cityName = "县";
        List<ChinaAreaCode> areaCodes3 = getAreaCode(provinceName, cityName);
        for (int i = 0; i < areaCodes3.size(); i++) {
            System.out.println(provinceName + " " + cityName + " area code : " + areaCodes3.get(i).getCode() + " " + areaCodes3.get(i).getArea());
        }
    }

    public static void syncAreaCodeFromWeb() {
        String html = connectWeb("http://www.ip33.com/area_code.html", "utf-8");
        parsersDomArea(html);
        saveAreaCodeLocal();
    }

    private static void saveAreaCodeLocal() {
        String jsonString = JSON.toJSONString(list);
        File file = new File(jsonFileName);
        BufferedWriter writer = null;
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        try {
            writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, false), "UTF-8"));
            writer.write(jsonString);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (writer != null) {
                    writer.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    public static void addChinaProvince(ChinaProvince province) {
        if (province == null) throw new RuntimeException("ChinaProvince is null");
        if (!list.contains(province)) {
            list.add(province);
        }
    }

    public static void loadChinaProvince() {
        File file = new File(jsonFileName);
        FileInputStream fis = null;
        BufferedReader reader = null;
        StringBuffer stringBuffer = null;
        try {
            fis = new FileInputStream(file);
            reader = new BufferedReader(new InputStreamReader(fis, "utf-8"));
            stringBuffer = new StringBuffer();
            String line = null;
            while ((line = reader.readLine()) != null) {
                stringBuffer.append(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (stringBuffer != null) {
            list = JSON.parseObject(stringBuffer.toString(), new TypeToken<List<ChinaProvince>>() {
            }.getType());
        }
    }

    public static List<ChinaProvince> getChinaProvinces() {
        return list;
    }

    public static List<String> getIdCardList(String verify, String province) {
        return getIdCardList(verify, 1949, province);
    }

    public static List<String> getIdCardList(String verify, int startYear, String province) {
        return getIdCardList(verify, startYear, province, null);
    }

    public static List<String> getIdCardList(String verify, int startYear, String province, String city) {
        return getIdCardList(verify, startYear, province, city, null);
    }

    public static List<String> getIdCardList(String verify, int startYear, String province, String city, String district) {
        List<String> idCardList = new ArrayList<>();
        List<ChinaAreaCode> areaCodes = getAreaCode(province, city, district);
        if (areaCodes == null || areaCodes.isEmpty()) {
            System.out.println("没有找到对应的省/直辖市/自治区: " + province);
        } else {
            List<String> dates = getDateFromYear(getDateFromString(startYear));
            for (int i = 0; i < areaCodes.size(); i++) {
                ChinaAreaCode areaCode = areaCodes.get(i);
                for (int j = 0; j < dates.size(); j++) {
                    idCardList.add(areaCode.getCode() + dates.get(j) + verify.toLowerCase());
                }
            }
        }
        return idCardList;
    }

    public static List<ChinaAreaCode> getAreaCode(String provinceName) {
        return getAreaCode(provinceName, null);
    }

    public static List<ChinaAreaCode> getAreaCode(String provinceName, String cityName) {
        return getAreaCode(provinceName, cityName, null);
    }

    public static List<ChinaAreaCode> getAreaCode(String provinceName, String cityName, String districtName) {
        if (list.isEmpty()) loadChinaProvince();
        List<ChinaAreaCode> areaCodes = new ArrayList<>();
        ChinaProvince province = null;
        for (int i = 0; i < list.size(); i++) {
            ChinaProvince p = list.get(i);
            if (p.getName().equals(provinceName)) {
                province = p;
                break;
            }
        }

        if (province != null) {
            if (cityName != null && !cityName.isEmpty()) {
                ChinaCity city = null;
                for (ChinaCity cc : province.getCityList()) {
                    if (cc.getName().equals(cityName)) {
                        city = cc;
                        break;
                    }
                }
                if (city != null) {
                    if (districtName != null && !districtName.isEmpty()) {
                        ChinaDistrict district = null;
                        for (ChinaDistrict d : city.getDistricts()) {
                            if (d.getName().equals(districtName)) {
                                district = d;
                                break;
                            }
                        }

                        if (district != null) {
                            ChinaAreaCode areaCode = new ChinaAreaCode();
                            areaCode.setArea(provinceName + city.getName() + district.getName());
                            areaCode.setCode(district.getCode());
                            areaCodes.add(areaCode);
                        } else {
                            for (int d = 0; d < city.getDistricts().size(); d++) {
                                ChinaDistrict cd = city.getDistricts().get(d);
                                ChinaAreaCode areaCode = new ChinaAreaCode();
                                areaCode.setArea(provinceName + city.getName() + cd.getName());
                                areaCode.setCode(cd.getCode());
                                areaCodes.add(areaCode);
                            }
                        }

                    } else {
                        for (int d = 0; d < city.getDistricts().size(); d++) {
                            ChinaDistrict cd = city.getDistricts().get(d);
                            ChinaAreaCode areaCode = new ChinaAreaCode();
                            areaCode.setArea(provinceName + city.getName() + cd.getName());
                            areaCode.setCode(cd.getCode());
                            areaCodes.add(areaCode);
                        }
                    }

                } else {
                    for (int c = 0; c < province.getCityList().size(); c++) {
                        ChinaCity tCity = province.getCityList().get(c);
                        for (int d = 0; d < tCity.getDistricts().size(); d++) {
                            ChinaDistrict cd = tCity.getDistricts().get(d);
                            ChinaAreaCode areaCode = new ChinaAreaCode();
                            areaCode.setArea(provinceName + tCity.getName() + cd.getName());
                            areaCode.setCode(cd.getCode());
                            areaCodes.add(areaCode);
                        }
                    }
                }
            } else {
                for (int c = 0; c < province.getCityList().size(); c++) {
                    ChinaCity city = province.getCityList().get(c);
                    for (int d = 0; d < city.getDistricts().size(); d++) {
                        ChinaDistrict cd = city.getDistricts().get(d);
                        ChinaAreaCode areaCode = new ChinaAreaCode();
                        areaCode.setArea(provinceName + city.getName() + cd.getName());
                        areaCode.setCode(cd.getCode());
                        areaCodes.add(areaCode);
                    }
                }
            }
        }

        return areaCodes;
    }

    public static String connectWeb(String address, String charsetName) {
        HttpURLConnection conn = null;
        URL url = null;
        InputStream in = null;
        BufferedReader reader = null;
        StringBuffer stringBuffer = null;
        try {
            url = new URL(address);
            conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(5000);
            conn.setDoInput(true);
            conn.connect();
            in = conn.getInputStream();
            reader = new BufferedReader(new InputStreamReader(in, charsetName));
            stringBuffer = new StringBuffer();
            String line = null;
            while ((line = reader.readLine()) != null) {
                stringBuffer.append(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            conn.disconnect();
            try {
                in.close();
                reader.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return stringBuffer.toString();
    }

    public static void parsersDomArea(String html) {

        Document document = Jsoup.parse(html);

        String splitRegex = " ";
        Pattern nameCodePattern = Pattern.compile("[\\u4e00-\\u9fa5]+ \\d+");

        //提取省/直辖市/自治区div标签集合
        Elements ipItems = document.getElementsByClass("ip");
        int ipSize = ipItems.size();

        for (int i = 0; i < ipSize; i++) {
            ChinaProvince chinaProvince = new ChinaProvince();
            Element areaElement = ipItems.get(i);
            Elements provinceElements = areaElement.getElementsByTag("h4");

            //提取省/直辖市/自治区
            Element province = provinceElements.first();

            Matcher provinceMatcher = nameCodePattern.matcher(province.html());
            if (provinceMatcher.find()) {
                String[] provinceInfo = provinceMatcher.group().split(splitRegex);
                chinaProvince.setName(provinceInfo[0]);
                chinaProvince.setCode(provinceInfo[1]);
                addChinaProvince(chinaProvince);
            }

            Element ulElement = areaElement.getElementsByTag("ul").first();
            Elements cityElements = ulElement.children();

            int citySize = cityElements.size();
            for (int j = 0; j < citySize; j++) {
                ChinaCity chinaCity = new ChinaCity();
                Element cityElement = cityElements.get(j);

                //提城市
                Element theCity = cityElement.getElementsByTag("h5").first();

                Matcher cityMatcher = nameCodePattern.matcher(theCity.html());
                if (cityMatcher.find()) {
                    String[] cityInfo = cityMatcher.group().split(splitRegex);
                    chinaCity.setName(cityInfo[0]);
                    chinaCity.setCode(cityInfo[1]);
                    chinaProvince.getCityList().add(chinaCity);
                }

                Elements districtElements = theCity.nextElementSibling().children();
                int districtSize = districtElements.size();

                for (int k = 0; k < districtSize; k++) {
                    ChinaDistrict chinaDistrict = new ChinaDistrict();
                    //提取区县
                    Element district = districtElements.get(k);
                    Matcher districtMatcher = nameCodePattern.matcher(district.html());
                    if (districtMatcher.find()) {
                        String[] districtInfo = districtMatcher.group().split(splitRegex);

                        chinaDistrict.setName(districtInfo[0]);
                        chinaDistrict.setCode(districtInfo[1]);
                        chinaCity.getDistricts().add(chinaDistrict);
                    }
                }
            }
        }
    }

    public static Date getDateFromString(int startYear) {
        String year = String.valueOf(startYear < 1900 ? 1900 : startYear);
        SimpleDateFormat sf = new SimpleDateFormat("yyyy");
        try {
            return sf.parse(year);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static List<String> getDateFromYear(Date startYear) {
        List<String> dates = new ArrayList<>();

        SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");

        Calendar startCalendar = Calendar.getInstance();
        startCalendar.setTime(new Date());
        while (true) {
            Date d = startCalendar.getTime();
            dates.add(df.format(startCalendar.getTime()));
            if (startYear == null) break;
            if (d.getTime() <= startYear.getTime()) break;
            startCalendar.add(Calendar.DAY_OF_MONTH, -1);
        }

        return dates;
    }

}
